package org.sosie2.service.authentication;

import java.io.IOException;
import java.io.UnsupportedEncodingException;

import javax.security.auth.callback.Callback;
import javax.security.auth.callback.UnsupportedCallbackException;

import org.apache.log4j.Logger;
import org.apache.ws.security.WSPasswordCallback;
import org.sosie2.service.framework.Utils;

import com.novell.ldap.LDAPConnection;
import com.novell.ldap.LDAPException;

/**
 * 
 * 
 * 
 * This is a custom callbackHandler invoked internally by the SecurityEngine in wsse, in order
 * to check a user/password pair. The "handle" method is overidden in order to check the password associated 
 * with the username, in a customary way. Here, a VerivyData object is used to retrieve the password from a LDAP
 * database mentained on the specified server.
 * @author Gabriela  
 */
public class LDAPCallbackHandler implements javax.security.auth.callback.Callback
{
	public VerifyData verifyData 			= new VerifyData();
	
	public LDAPCallbackHandler()
	{
		super();
		
	}	
	public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException 
	{
		System.out.println("Entering CallbackHandler");
		
		for (int i = 0; i < callbacks.length; i++) {
			if (callbacks[i] instanceof WSPasswordCallback) {
				
				WSPasswordCallback pc = (WSPasswordCallback) callbacks[i];
				String userName = pc.getIdentifer();
							
				String args[] = new String[] {Utils.LDAP_SERVER, Utils.LDAP_DOMAIN, "cn="+userName + ","+ Utils.LDAP_DOMAIN};
				String password = this.verifyData.getPwd(args, null);
				pc.setPassword(password);	
				
			} else {
				throw new UnsupportedCallbackException(callbacks[i],"Unrecognized Callback");
			}
		}
	
	}
}


/**
 * 
 * @author gabriela
 * Given a username and a password, this object checks the LDAP directory for the correctness of the data:
 * the username-password pair.
 */

class VerifyData
{
    public String getPwd(String[] args, Logger logger) 
    {        
        if (args.length != 3) {
           logger.warn("<host name>"+ "<login dn> <object dn>\n");
           logger.info("Example: localhost:389 " + "\"cn=Admin,o=Acme\" " 
                       + "\"cn=JSmith,ou=Sales,o=Acme\" ");   
        }

        int ldapPort = LDAPConnection.DEFAULT_PORT;
        int ldapVersion = LDAPConnection.LDAP_V3;
        String ldapHost = args[0];
        String loginDN = args[1];
        String password = "";
        String objectDN = args[2];
        LDAPConnection lc = new LDAPConnection();

        try {
           // connect to the server
            lc.connect( ldapHost, ldapPort );
           // authenticate to the server
            lc.bind( ldapVersion, loginDN, password.getBytes("UTF8") );
            password = lc.read(objectDN).getAttribute("userPassword").getStringValue();
           // disconnect with the server
            lc.disconnect();

        }
        catch( LDAPException e ) 
        {
            if ( e.getResultCode() == LDAPException.NO_SUCH_OBJECT ) 
            {
                logger.warn( "Error: No such entry" );
            } 
            else if ( e.getResultCode() == LDAPException.NO_SUCH_ATTRIBUTE ) 
            {
                logger.warn( "Error: No such attribute" );
            } 
            else            	
            {
                logger.warn( "Error: " + e.toString() );
            }        
        }
        catch( UnsupportedEncodingException e ) 
        {
            logger.warn( "Error: " + e.toString() );
        }       
        
        return password;
    }
    
}